<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index12-工厂函数和构造函数</title>
</head>
<body>
<script type="text/javascript">

  // 之前生成对象
  // var person1 = {
  //   name: "张三",
  //   age: 20,
  //   gender: "男",
  //   show: function(){
  //     console.log(`${this.name},${this.age},${this.gender}`);
  //   }
  // };
  // person1.show();
  //
  // var person2 = {
  //   name: "张三2",
  //   age: 22,
  //   gender: "女",
  //   show: function(){
  //     console.log(`${this.name},${this.age},${this.gender}`);
  //   }
  // };
  // person2.show();

  // 使用工厂函数来生成对象,创建人的对象
  // function createFactory(name, age, gender){
  //   var person = new Object();
  //   person.name = name;
  //   person.age = age;
  //   person.gender = gender;
  //   person.show = function(){
  //     console.log(`${this.name},${this.age},${this.gender}`);
  //   }
  //   return person;
  // }
  // // 工厂函数来创建
  // var p1 = createFactory("张三", 20, "男");
  // // var p2 = createFactory("李四", 21, "女");
  // // p1.show();
  // // p2.show();
  // var d = createFactory("大黄", 3, "公");
  // d.show();
  // console.log(p1 instanceof Object);
  // console.log(d instanceof  Object);

  // 工厂函数在使用时可以创建对象，并且能够封装创建对象过程，但是类型不明确，都是Object,由此推出了构造函数
  // 构造函数，本质也是一种函数，需要跟普通函数区分开
  // 1.构造函数的首字母需要大写
  // 2.构造函数需要通过new关键字来调用，当前构造函数直接直接调用，不会直接调用
  // 需求：定义一个人的构造函数,有三个参数:name,age,gender

  // function show(){
  //     console.log(`${this.name},${this.age},${this.gender}`);
  // }

  function Person(name, age, gender) {
      // this代表调用者本身
      // window.Person();===》当前函数中的this指向的是window
      console.log(this);
      this.name = name;
      this.age = age;
      this.gender = gender;
      // this.show = function(){
      //     console.log(`${this.name},${this.age},${this.gender}`);
      // };
      // this.show = show;
  }
  // 使用原型来添加方法/函数,prototype原型
  // console.log(Person.prototype);
  // Person.prototype.show = function(){
  //     console.log(`${this.name},${this.age},${this.gender}`);
  // };
  //
  // // Person构造函数可以直接调用
  // // Person("张三", 20, "男");// 相当于window.Person();
  //   var p1 = new Person("张三", 20, "男");
  // // console.log(p1 instanceof Person);
  // // console.log(p1 instanceof Object);
  // // p1.show();
  //   var p2 = new Person("李四", 21, "女");
  // console.log(p1);
  // console.log(p2);
  // console.log(p1.show == p2.show);

  // 原型链：完成继承的作用
  // 动物的构造函数
  // function Animal(){
  //     this.name = "哈哈";
  // }
  // // 给Animal的原型来添加属性和方法
  // Animal.prototype.name = "小黑";
  // Animal.prototype.age = 20;
  // Animal.prototype.show = function(){
  //     console.log(`${this.name},${this.age}`);
  // };
  //
  // // 使Dog继承Animal
  // function Dog(){
  // }
  // // 指定Dog的原型对象是Animal的实例对象
  // Dog.prototype = new Animal();
  // // 修改Dog的原型对象构造器,constructor构造器
  // Dog.prototype.constructor = Dog;
  // // 重写
  // // Dog.prototype.show = function(){
  // //     console.log("Dog的show函数")
  // // };
  // // 输出Dog的原型对象
  // // console.log(Dog.prototype);
  // // 创建Dog的对象
  // var dog = new Dog();
  // console.log(dog.name);
  // console.log(dog.age);
  // dog.show();

  // 组合继承：通过原型链完成方法继承，通过借用构造完成属性继承
  // 定义Animal构造函数，有三个属性：name,age,gender,有一个方法show自我介绍
  // 定义一个子类Dog,对于name,age,gender要去继承Animal，对于健康值health不需要继承Animal,对于方法的继承需要通过原型链来完成
  // 再定义一个子类Cat,对于name,age,gender要去继承Animal,对于亲密度love不需要继承Animal，对于方法的继承需要通过原型链来完成
  function Animal(name, age, gender){
      this.name = name;
      this.age = age;
      this.gender = gender;
  }
  Animal.prototype.show = function(){
      console.log(`${this.name},${this.age},${this.gender}`);
  };
  function Dog(name, age, gender, health){
      // 通过借用构造完成属性继承
      // call(this,a,b,c)：this代表传到指定构造函数的中当前都西昂
      Animal.call(this, name, age, gender);
      // 定义特有属性
      this.health = health;
  }
  // 通过原型链完成方法继承
  Dog.prototype = new Animal();
  // 修改Dog原型对象构造器
  Dog.prototype.constructor = Dog;
  // 重写Animal原型中的show方法
  Dog.prototype.show = function(){
      console.log(`${this.name},${this.age},${this.gender},${this.health}`);
  };
  // 测试
  var dog = new Dog("小黑", 4, "公", 90);
  dog.show();

  function Cat(name, age, gender, love){
      Animal.call(this, name, age, gender);
      this.love = love;
  }
  Cat.prototype = new Animal();
  Cat.prototype.constructor = Cat;
  Cat.prototype.show = function(){
      console.log(`${this.name},${this.age},${this.gender},${this.love}`);
  };
  var tom = new Cat("tom",3, "公", 80);
  tom.show();
</script>
</body>
</html>